﻿#pragma once
#include "engine\object_api.h"
#include <sstream>

#define EX_BEGIN_INTERFACE_MAP()											\
	EXMETHOD HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override {	

#define EX_END_INTERFACE_MAP()										\
		ppvObject = nullptr;										\
		return E_NOINTERFACE;										\
	}																\
	template<class QI>												\
	inline HRESULT STDMETHODCALLTYPE QueryInterface(QI** ppv) {				\
		return this->QueryInterface(__uuidof(QI), (void**)ppv);		\
	}

#define EX_INTERFACE_ENTRY(Interface)						\
	if (IsEqualIID(riid, __uuidof(Interface))) {		\
		*ppvObject = static_cast<Interface*>(this);		\
		static_cast<Interface*>(this)->AddRef();		\
		return S_OK;									\
	}

#define EX_INTERFACE_ENTRY2(Interface,InterfaceType)		\
	if (IsEqualIID(riid, __uuidof(Interface))) {			\
		*ppvObject = static_cast<InterfaceType*>(this);		\
		static_cast<InterfaceType*>(this)->AddRef();		\
		return S_OK;										\
	}

#define EX_INTERFACE_MULTI_IMPLIMENT()										\
	EXMETHOD ULONG STDMETHODCALLTYPE AddRef() override {							\
		return ExObjectBase::AddRef();										\
	}																		\
	EXMETHOD ULONG STDMETHODCALLTYPE Release() override {							\
		return ExObjectBase::Release();										\
	}
	

namespace JOUI
{
	template<class Interface>
	class ExObjectImpl : public Interface
	{
	public:
		virtual ~ExObjectImpl() {}

	public:

		// IUnknown

		EXMETHOD ULONG STDMETHODCALLTYPE AddRef() override
		{
			return InterlockedIncrement(&m_object_ref_count);
		}
		EXMETHOD ULONG STDMETHODCALLTYPE Release() override
		{
			ULONG ref_count = InterlockedDecrement(&m_object_ref_count);
			if (ref_count == 0) {
				FinalRelease();
			}
			return ref_count;
		}


	protected:
		EXMETHOD void STDMETHODCALLTYPE FinalRelease() { delete this; }
	private:
		ULONG m_object_ref_count{ 1 };
	};

	using ExObjectBase = ExObjectImpl<IObject>;
}
